﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.Serialization;
using System.Xml.Serialization;

namespace Cubicle.Core.Shared
{

    public class DynamicPropertyChangedEventArgs : PropertyChangedEventArgs
    {
        public DynamicItem Target;

        public DynamicPropertyChangedEventArgs(DynamicItem target, string propertyName)
            : base(propertyName)
        {
            Target = target;
        }
    }

    [DataContract]
    [Serializable]
    public class DynamicItem : INotifyPropertyChanged
    {
    
        [XmlIgnore]
        protected readonly ConcurrentDictionary<string, object> Properties = new ConcurrentDictionary<string, object>();

        public T Get<T>(string propertyName, T failValue)
        {
            object result = null;
            Properties.TryGetValue(propertyName, out result);
            if (result == null) return failValue;
            if (!(result is T))
                throw new InvalidCastException(
                    String.Format("Could not cast dynamic property to required type. RequiredType = {0}", typeof(T).FullName));
            return (T) result;
        }

        public void Set<T>(string propertyName, T value)
        {
            Properties[propertyName] = value;
            PropertyChanged(this, new DynamicPropertyChangedEventArgs(this, propertyName));
        }
        
        public IEnumerable<string> ListProperties()
        {
            return Properties.Keys;
        }

        #region Implementation of INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged = delegate {};

        #endregion

        public void RaisePropertyChanged(object sender, string propertyName)
        {
            PropertyChanged(sender, new DynamicPropertyChangedEventArgs(this, propertyName));
        }

    }
}